﻿
Imports System.Threading
Imports osi.root.utils
Imports osi.root.delegates
Imports osi.root.lock
Imports osi.root.connector

Public Class multithreading_case_wrapper
    Inherits case_wrapper

    Private ReadOnly tc As Int32 = 0
    Private running_thread As Int64 = 0
    Private accepted As Boolean = False
    Private failed As Boolean = False

    Public Sub New(ByVal c As [case], Optional ByVal threadcount As Int32 = 8)
        MyBase.New(c)
        Me.tc = threadcount
    End Sub

    Public NotOverridable Overrides Function preserved_processors() As Int16
        Return threadcount()
    End Function

    Protected Overridable Function threadcount() As Int32
        Return tc
    End Function

    Private Function thread_accept() As Boolean
        Interlocked.Increment(running_thread)
        timeslice_sleep_wait_until(Function() accepted OrElse failed)
        Return accepted
    End Function

    Private Function waitfor_running_thread(ByVal d As _do(Of Int32, Boolean)) As Boolean
        assert(Not d Is Nothing)
        Return d(atomic.read(running_thread))
    End Function

    Private Function waitfor_running_thread_started() As Boolean
        Return waitfor_running_thread(Function(ByRef x) x < threadcount())
    End Function

    Private Function waitfor_running_thread_finished() As Boolean
        Return waitfor_running_thread(Function(ByRef x) x > 0)
    End Function

    Private Sub workon()
        If thread_accept() Then
            If Not do_(AddressOf MyBase.run, False) Then
                failed = True
            End If
            Interlocked.Decrement(running_thread)
        End If
    End Sub

    Public NotOverridable Overrides Function run() As Boolean
        assert(Me.threadcount() > 1 OrElse envs.single_cpu)
        accepted = False
        failed = False
        Dim ts() As Thread = Nothing
        ReDim ts(threadcount() - 1)
        For i As Int32 = 0 To threadcount() - 1
            ts(i) = New Thread(AddressOf workon)
            ts(i).Name() = "MULTITHREADING_CASE_WRAPPER_THREAD"
            ts(i).Start()
        Next
        Dim wait_round As Int32 = 1000
        timeslice_sleep_wait_when(Function() waitfor_running_thread_started() AndAlso _dec(wait_round) > 0)
        If waitfor_running_thread_started() Then
            failed = True
            Return False
        Else
            accepted = True
            Using New thread_lazy()
                timeslice_sleep_wait_when(AddressOf waitfor_running_thread_finished)
            End Using
            For i As Int32 = 0 To threadcount() - 1
                ts(i).Abort()
                ts(i).Join()
            Next
            Return Not failed
        End If
    End Function
End Class
